/**  
* Copyright (c) 2008, Noel Lynch All rights reserved. Redistribution and use  
* in source and binary forms, with or without modification, are permitted  
* provided that the following conditions are met: Redistributions of source  
* code must retain the above copyright notice, this list of conditions and the  
* following disclaimer. Redistributions in binary form must reproduce the above  
* copyright notice, this list of conditions and the following disclaimer in the  
* documentation and/or other materials provided with the distribution. Neither  
* the name of Noel Lynch nor the names of contributors may be used to  
* endorse or promote products derived from this software without specific prior  
* written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT  
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A  
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR  
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,  
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;  
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR  
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF  
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
*/
// Jul 29, 2008

package com.sceneworker.monitorpopup;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.concurrent.Callable;

import javax.swing.JDialog;
import javax.swing.JMenu;
import javax.swing.tree.TreePath;

import com.jme.scene.Controller;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.TriMesh;
import com.jme.system.DisplaySystem;
import com.jme.util.GameTaskQueueManager;
import com.jme2utils.objects.AdjustYController;
import com.jme2utils.staticutils.GenericJMEUtils;
import com.jme2utils.staticutils.MeshUtils;
import com.jme2utils.staticutils.TextureUtils;
import com.myjavautils.GenericUtils;
import com.sceneworker.app.globals.SceneWorkerDialogManager;
import com.sceneworker.app.globals.SceneWorkerGlobals;
import com.sceneworker.app.globals.cacheobjects.RootNodeCacheObject;
import com.sceneworker.editors.beanshelleditor.BeanShellOneOffScriptPanel;
import com.sceneworker.monitorpopup.panels.CopyTextureCoordsPanel;
import com.sceneworker.monitorpopup.panels.NewControllerPanel;
import com.sceneworker.monitorpopup.panels.NewRenderStatePanel;

public class SpatialMenu extends BaseMenu implements ActionListener {

	private static final String DROP_SPATIAL_TO_BOUNDS = "Drop Spatial To Bounds";
	private static final String DO_TEST_THING = "Do Test Thingy";
	private static final String DROP_SPATIAL_TO_GROUND = "Drop Spatial To Ground";
	private static final String RESTART_ALL_CONTROLLERS = "Restart All Controllers";
	private static final String INVERT_NORMALS = "Invert Normals";
	private static final String RECALCULATE_NORMALS = "Recalculate Normals";
	private static final String EXECUTE_BEAN_SHELL_SCRIPT_ON_OBJECT = "Execute Bean Shell Script On Object";
	private static final String FOLLOW_WITH_CAMERA = "Track Camera";
	private static final String UPDATE_RENDER_GEOMETRY_BOUND = "Update Render State, Geometry, Bound";
	private static final String NEW_CONTROLLER = "New Controller";
	private static final String IMPORT_CONTROLLER = "Import Controller";
	private static final String NEW_RENDER_STATE = "New RenderState";
	private static final String IMPORT_RENDER_STATE = "Import RenderState";
	private static final String LOAD_TEXTURE = "Load Texture";
	private static final String ENABLE_TRANSPARENCY = "Enable Transparency";
	private static final String COPY_TEXTURE_CORDINATES = "Copy Texture Cordinates";
	
	private		Spatial		mcl_spatial;
	
	public
	SpatialMenu(TreePath cl_selectedPath, SceneWorkerPopUp cl_menu) {
		super(cl_menu);
		mcl_spatial = (Spatial)cl_selectedPath.getLastPathComponent();
		
		buildMenu();
	}
	
	@Override
	protected	void
	buildMenu() {
		mcl_menu.addSeparator();
		mcl_menu.add(buildAMenuItem(NEW_RENDER_STATE));
		mcl_menu.add(buildAMenuItem(NEW_CONTROLLER));
		
		mcl_menu.addSeparator();
		
		JMenu		lcl_utilsMenu = new JMenu("Utils");
		
		lcl_utilsMenu.add(buildAMenuItem(LOAD_TEXTURE));
		lcl_utilsMenu.add(buildAMenuItem(ENABLE_TRANSPARENCY));
		lcl_utilsMenu.add(buildAMenuItem(UPDATE_RENDER_GEOMETRY_BOUND));
		lcl_utilsMenu.add(buildAMenuItem(FOLLOW_WITH_CAMERA));
		lcl_utilsMenu.add(buildAMenuItem(EXECUTE_BEAN_SHELL_SCRIPT_ON_OBJECT));
		lcl_utilsMenu.add(buildAMenuItem(RECALCULATE_NORMALS));
		lcl_utilsMenu.add(buildAMenuItem(INVERT_NORMALS));
		lcl_utilsMenu.add(buildAMenuItem(COPY_TEXTURE_CORDINATES));
		lcl_utilsMenu.add(buildAMenuItem(RESTART_ALL_CONTROLLERS));
		lcl_utilsMenu.add(buildAMenuItem(DROP_SPATIAL_TO_GROUND));
		lcl_utilsMenu.add(buildAMenuItem(DROP_SPATIAL_TO_BOUNDS));
		//lcl_utilsMenu.add(buildAMenuItem(DO_TEST_THING));
		
		mcl_menu.add(lcl_utilsMenu);
	}

	public void actionPerformed(ActionEvent cl_e) {
		
		if(cl_e.getActionCommand().equals(COPY_TEXTURE_CORDINATES)) {
			JDialog		lcl_dlg = SceneWorkerDialogManager.inst().makeADialog(SceneWorkerDialogManager.COPY_TEXTURE_COORDINATES_DIALOG);
			CopyTextureCoordsPanel		lcl_panel = new CopyTextureCoordsPanel(mcl_spatial, lcl_dlg);
			lcl_dlg.add(lcl_panel);
			lcl_dlg.setVisible(true);
			return;
		}
		
		if(cl_e.getActionCommand().equals(NEW_RENDER_STATE)) {
			JDialog		lcl_dlg = SceneWorkerDialogManager.inst().makeADialog(SceneWorkerDialogManager.NEW_RENDER_STATE_DIALOG);
			lcl_dlg.add(new NewRenderStatePanel(mcl_spatial, lcl_dlg));
			lcl_dlg.setVisible(true);
			
			return;
		}
		
		if(cl_e.getActionCommand().equals(NEW_CONTROLLER)) {
			JDialog		lcl_dlg = SceneWorkerDialogManager.inst().makeADialog(SceneWorkerDialogManager.NEW_CONTROLLER_DIALOG);
			lcl_dlg.add(new NewControllerPanel(lcl_dlg, mcl_spatial));
			lcl_dlg.setVisible(true);
			
			return;
		}
		
		if(cl_e.getActionCommand().equals(EXECUTE_BEAN_SHELL_SCRIPT_ON_OBJECT)) {
			JDialog		lcl_dlg = SceneWorkerDialogManager.inst().makeADialog(SceneWorkerDialogManager.BEAN_SHELL_EDITOR_DIALOG);
			lcl_dlg.add(new BeanShellOneOffScriptPanel(lcl_dlg, mcl_spatial));
			lcl_dlg.setVisible(true);
			return;
		}
		
		if(cl_e.getActionCommand().equals(LOAD_TEXTURE)) {
			final	File		lcl_f = GenericUtils.getAnImageFile(null);
			if(lcl_f == null) {
				return;
			}
			
			GameTaskQueueManager.getManager().update(new Callable<Void>() {
				public Void call() throws Exception {
					TextureUtils.addTextureToSpatial(mcl_spatial, lcl_f);
					return null;
				}
			});
		}
		
		if(cl_e.getActionCommand().equals(ENABLE_TRANSPARENCY)) {
			GameTaskQueueManager.getManager().update(new Callable<Void>() {
				public Void call() throws Exception {
					GenericJMEUtils.enableTransparency(mcl_spatial);
					return null;
				}
				
			});
		}
		
		if(cl_e.getActionCommand().equals(UPDATE_RENDER_GEOMETRY_BOUND)) {
			GameTaskQueueManager.getManager().update(new Callable<Void>() {

				public Void call() throws Exception {
					mcl_spatial.updateRenderState();
					mcl_spatial.updateModelBound();
					mcl_spatial.updateGeometricState(0, true);
					return null;
				}
				
			});
		}
		
		if(cl_e.getActionCommand().equals(RECALCULATE_NORMALS)) {
			GameTaskQueueManager.getManager().update(new Callable<Void>() {
				public Void call() throws Exception {
					recalculateNormals(mcl_spatial);
					return null;
				}
				
			});
		}
		
		if(cl_e.getActionCommand().equals(INVERT_NORMALS)) {
			GameTaskQueueManager.getManager().update(new Callable<Void>() {
				public Void call() throws Exception {
					invertNormals(mcl_spatial);
					return null;
				}
				
			});
		}
		
		if(cl_e.getActionCommand().equals(RESTART_ALL_CONTROLLERS)) {
			GameTaskQueueManager.getManager().update(new Callable<Void>() {
				public Void call() throws Exception {
					restartAllControllers();
					return null;
				}
			});
		}
		
		if(cl_e.getActionCommand().equals(FOLLOW_WITH_CAMERA)) {
			mcl_spatial.addController(new Controller() {
				@Override
				public void update(float time) {
					mcl_spatial.setLocalTranslation(DisplaySystem.getDisplaySystem().getRenderer().getCamera().getLocation());
				}
			});
		}
		
		if(cl_e.getActionCommand().equals(DROP_SPATIAL_TO_GROUND)) {
			GameTaskQueueManager.getManager().update(new Callable<Void>() {
				public Void call() throws Exception {
					RootNodeCacheObject		lcl_root = (RootNodeCacheObject)SceneWorkerGlobals.inst().getFromCache("rootNode");
					AdjustYController		lcl_controller = new AdjustYController((Node)lcl_root.getValue(), mcl_spatial, true);
					if(lcl_controller.hasCollide()) {
						mcl_spatial.addController(lcl_controller);
					}
					
					return null;
				}
				
			});
		}
		
		if(cl_e.getActionCommand().equals(DROP_SPATIAL_TO_BOUNDS)) {
			GameTaskQueueManager.getManager().update(new Callable<Void>() {
				public Void call() throws Exception {
					RootNodeCacheObject		lcl_root = (RootNodeCacheObject)SceneWorkerGlobals.inst().getFromCache("rootNode");
					AdjustYController		lcl_controller = new AdjustYController((Node)lcl_root.getValue(), mcl_spatial, false);
					if(lcl_controller.hasCollide()) {
						mcl_spatial.addController(lcl_controller);
					}
					
					return null;
				}
				
			});
		}
		
		if(cl_e.getActionCommand().equals(DO_TEST_THING)) {
			GameTaskQueueManager.getManager().update(new Callable<Void>() {
				public Void call() throws Exception {
					System.out.println(GenericJMEUtils.inspectWorldData(mcl_spatial));
					return null;
				}
			});
		}
	}
	
	private	void	restartAllControllers() {
		ArrayList<Controller>		lcla_controllers = new ArrayList<Controller>();
		
		getAllControllers(lcla_controllers, mcl_spatial);
		
		for(Controller lcl_controller : lcla_controllers) {
			lcl_controller.setMinTime(0);
			lcl_controller.update(0);
		}
		
	}
	
	private	void	getAllControllers(ArrayList<Controller> cla_controllers, Spatial cl_s) {
		for(Controller lcl_controller : cl_s.getControllers()) {
			cla_controllers.add(lcl_controller);
		}
		
		if(cl_s instanceof Node) {
			for(Spatial lcl_child : ((Node)cl_s).getChildren()) {
				getAllControllers(cla_controllers, lcl_child);
			}
		}
	}
	
	private	void	recalculateNormals(Spatial cl_s) {
		if(cl_s instanceof TriMesh) {
			MeshUtils.recalculateNormals((TriMesh)cl_s);
		} else if(cl_s instanceof Node) {
			for(Spatial lcl_child : ((Node)cl_s).getChildren()) {
				recalculateNormals(lcl_child);
			}
		}
	}
	
	private	void	invertNormals(Spatial cl_s) {
		if(cl_s instanceof TriMesh) {
			MeshUtils.invertNormals((TriMesh)cl_s);
		} else if(cl_s instanceof Node) {
			for(Spatial lcl_child : ((Node)cl_s).getChildren()) {
				invertNormals(lcl_child);
			}
		}
	}

}
